<template>
  <div>
    <div id="table-time-selected" class="table-time-selected">
      <table border="0" class="plug-timer-grid">
        <thead>
          <tr>
            <th rowspan="2" class="pull-left-info">星期\时间</th>
            <th colspan="24">00:00 - 12:00</th>
            <th colspan="24">12:00 - 24:00</th>
          </tr>
          <tr>
            <template v-for="index in 24">
              <td colspan="2" :key="index" @click="hoursColumnBar" :hourIndex="index">{{index-1}}</td>
            </template>
          </tr>
        </thead>
        <tbody class="timeTableTbody">
          <template v-for="item in weekArray">
            <tr :key="item.id+1">
              <th
                :weekIndex="(item.id)+1"
                @click="weekColumnBar"
                class="pull-left-info"
              >{{item.value}}</th>
              <template v-for="timeIndex in 48">
                <td
                  :id="(item.id)+1+'_'+ timeIndex"
                  :key="timeIndex"
                  @mousedown="tdMouseDown(timeIndex,(item.id)+1)"
                  :ref="(item.id)+1+'_'+ timeIndex"
                  :value="(item.id)+1+'_'+timeIndex"
                  :weekIndex="(item.id)+1"
                  :timeIndex="timeIndex"
                  class="showTip"
                ></td>
              </template>
            </tr>
          </template>
          <tr>
            <td colspan="49" class="table-footer">
              <div class="duration-tipline">
                <div class="left">
                  <span class="color-box"></span>
                  <span>未选</span>
                </div>
                <span class="color-box color-blue"></span>
                <span>已选</span>
                <span class="weektip">可拖动鼠标选择时间段</span>
                <a class="emptied" @click="clearAll">清空</a>
              </div>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>
<script>
import $ from "jquery";
import _ from "lodash";
import $layer from "layui-layer";
export default {
  props: {
    defaultBinaryTime: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      box_id: "table-time-selected",
      defaultTipColor: "rgb(32,45,61)",
      startTd: null,
      startTdIndex: null,
      endTd: null,
      endTdIndex: null,
      selectedCls: "time-selected",
      startX: null,
      startY: null,
      hour: null, //点击中表格的小时值
      tdState: 0, //1为这个格子在此次鼠标拖拽过程中被选中（不执行选中方法），0为没选中过
      weekData: ["一", "二", "三", "四", "五", "六", "日"], //生成星期数组
      timeSlot: [],
      timeWeekArr: [],
      displayHtml: "",
      timeBinary: [],
      weekArray: [
        {
          id: 0,
          value: "星期一"
        },
        {
          id: 1,
          value: "星期二"
        },
        {
          id: 2,
          value: "星期三"
        },
        {
          id: 3,
          value: "星期四"
        },
        {
          id: 4,
          value: "星期五"
        },
        {
          id: 5,
          value: "星期六"
        },
        {
          id: 6,
          value: "星期日"
        }
      ]
    };
  },
  created() {
    this.timeSlot = this.getTimeSlot();
  },
  mounted() {
    this.binarySelected();
    $(".plug-timer-grid").on("mouseover", ".showTip", e => {
      let weekIndex = +$(e.currentTarget).attr("weekindex");
      let hourIndex = +$(e.currentTarget).attr("timeindex") - 1;
      let hasClass = $("#" + weekIndex + "_" + (hourIndex + 1)).hasClass(
        this.selectedCls
      );
      if (!hasClass) {
        $("#" + weekIndex + "_" + (hourIndex + 1)).addClass("tdmouse-hover");
      }
      let tempTip = this.weekArray[weekIndex - 1].value;
      let tempTime = null;
      _.forEach(this.timeSlot, (value, index) => {
        if (hourIndex === index) {
          tempTime = value.split(":");
          let halfTotalMinutes = this.calculationMinutes(
            tempTime[0],
            tempTime[1]
          );
          let transFormHalf = this.transFormMinuteToHour(
            +halfTotalMinutes - 30
          );
          $layer.tips(
            tempTip + " " + transFormHalf + "-" + value,
            `${"#" + weekIndex + "_" + (hourIndex + 1)}`,
            {
              tips: [1, this.defaultTipColor],
              time: 0
            }
          );
          return;
        }
      });
    });
    $(".plug-timer-grid").on("mouseleave", ".showTip", e => {
      let weekIndex = +$(e.currentTarget).attr("weekindex");
      let hourIndex = +$(e.currentTarget).attr("timeindex") - 1;
      $("#" + weekIndex + "_" + (hourIndex + 1)).removeClass("tdmouse-hover");
      $layer.closeAll("tips");
    });
  },
  methods: {
    clearAll() {
      //清除所有选中项
      $(".timeTableTbody")
        .find("td")
        .removeClass(this.selectedCls);
      this.refreshTable();
    },
    hoursColumnBar(e) {
      // 点击小时栏
      this.hour = $(e.currentTarget).attr("hourIndex");
      if (this.hour >= 0) {
        let rows = $("#" + this.box_id + " table tbody tr").length;
        this.startX = +$(e.currentTarget).attr("hourIndex") * 2 - 1;
        this.startY = 0;
        this.startTdIndex = {
          x: this.startX,
          y: this.startY
        };
        this.endTd = $(e.currentTarget);
        let x = +$(e.currentTarget).attr("hourIndex") * 2 - 2;
        let y = rows - 1; //为了配合for计算公式-1
        this.endTdIndex = {
          x: x,
          y: y
        };
        //改变第一次按下鼠标时候的改变选中状态
        this.selectTdClick(
          this.startTdIndex,
          this.endTdIndex,
          this.selectedCls
        );
      }
    },
    weekColumnBar(e) {
      // 点击 星期栏
      let week = $(e.currentTarget).attr("weekIndex");
      if (week >= 0) {
        let line =
          $("#" + this.box_id + " table tbody tr td").length /
          ($("#" + this.box_id + " table tbody tr").length - 1);
        this.startX = 0;
        this.startY = +$(e.currentTarget).attr("weekIndex") - 1;
        this.startTdIndex = {
          x: this.startX,
          y: this.startY
        };

        this.endTd = $(e.currentTarget);
        let y = $(e.currentTarget).attr("weekIndex") - 1;
        let x = line - 1; //为了配合for计算公式-1
        this.endTdIndex = {
          x: x,
          y: y
        };
        //改变第一次按下鼠标时候的改变选中状态
        this.selectTdClick(
          this.startTdIndex,
          this.endTdIndex,
          this.selectedCls
        );
      }
    },
    tdMouseDown(timeIndex, weekIndex) {
      //监听鼠标按下事件(鼠标按下左键拖动选中处理块)
      this.startX = timeIndex - 1;
      this.startY = weekIndex - 1;
      this.startTdIndex = {
        x: this.startX,
        y: this.startY
      };

      this.endTd = this.$refs[weekIndex + "_" + timeIndex];
      let x = timeIndex - 1;
      let y = weekIndex - 1;
      this.endTdIndex = {
        x: x,
        y: y
      };
      //改变第一次按下鼠标时候的改变选中状态
      this.selectTD(this.startTdIndex, this.endTdIndex, this.selectedCls);
      this.startTd = this.$refs[weekIndex + "_" + timeIndex];
      this.startTdIndex = {
        x: this.startX,
        y: this.startY
      };
      $("#" + this.box_id + " table tbody tr td").mouseover(e => {
        //监听鼠标移动事件，实现改变后续鼠标拖拽时候的表格选中状态
        this.endTd = e.currentTarget;
        let x = $(e.currentTarget).attr("timeIndex") - 1;
        let y = $(e.currentTarget).attr("weekIndex") - 1;
        this.endTdIndex = {
          x: x,
          y: y
        };
        if (1 !== e.which) {
          //判断是否为左击
          $("#" + this.box_id + " table tbody tr td").unbind("mouseover");
        }
        this.selectTD(this.startTdIndex, this.endTdIndex, this.selectedCls);
      });
      //放开鼠标左键时，初始化相关参数和解绑相关监听
      $(".table-time-selected")
        .unbind("mouseup")
        .bind("mouseup", () => {
          this.refreshTable();
        });
    },
    getTimeSlot() {
      //获取一天中的时间段[24*2]
      let arrHour = [];
      let oDate = new Date();
      oDate.setHours(0);
      oDate.setMinutes(0);
      oDate.setSeconds(0);
      oDate.setMilliseconds(0);
      let oDate_hour = oDate.getHours();
      let oDate_minute = oDate.getMinutes();
      _.times(48, i => {
        oDate.setMinutes(oDate.getMinutes() + 30);
        oDate_hour = oDate.getHours();
        oDate_minute = oDate.getMinutes();
        if (i === 47 && oDate_hour === 0) {
          oDate_hour = 24;
        }
        oDate_minute = oDate_minute.toString().padStart(2, "0");
        oDate_hour = oDate_hour.toString().padStart(2, "0");
        arrHour[i] = oDate_hour + ":" + oDate_minute;
      });
      return arrHour;
    },
    //按下鼠标左键拖动选中单元格
    selectTD(startTdIndex, endTdIndex, selectedCls) {
      let MinX = null;
      let MaxX = null;
      let MinY = null;
      let MaxY = null;

      let coordinate = this.getCoordinate(startTdIndex, endTdIndex);
      MinX = coordinate[0];
      MaxX = coordinate[1];
      MinY = coordinate[2];
      MaxY = coordinate[3];
      for (let i = MinY; i <= MaxY; i++) {
        for (let j = MinX; j <= MaxX; j++) {
          let selectTR = $("#" + this.box_id + " table tbody tr ").eq(i);
          let td_class = $("td", selectTR)
            .eq(j)
            .attr("class");
          this.tdState = $("td", selectTR)
            .eq(j)
            .attr("tdState");
          //在同一次鼠标按下的过程中，选中过的表格不进行选中或取消操作
          if (!this.tdState) {
            if (td_class.indexOf(this.selectedCls) != -1) {
              $("td", selectTR)
                .eq(j)
                .removeClass(this.selectedCls);
            } else {
              //筛选掉标明为星期的表格
              $("td", selectTR)
                .eq(j)
                .removeClass("tdmouse-hover")
                .addClass(this.selectedCls);
            }
            $("td", selectTR)
              .eq(j)
              .attr("tdState", "1");
          }
        }
      }
      //改变二进制值
      this.changeTimeBinary();
      //改变日期显示
      this.getBinaryConvertDate();
    },
    //获取选中范围的开始与结束的坐标
    getCoordinate(startTdIndex, endTdIndex) {
      let MinX = null;
      let MaxX = null;
      let MinY = null;
      let MaxY = null;
      if (startTdIndex.x < endTdIndex.x) {
        MinX = startTdIndex.x;
        MaxX = endTdIndex.x;
      } else {
        MinX = endTdIndex.x;
        MaxX = startTdIndex.x;
      }
      if (startTdIndex.y < endTdIndex.y) {
        MinY = startTdIndex.y;
        MaxY = endTdIndex.y;
      } else {
        MinY = endTdIndex.y;
        MaxY = startTdIndex.y;
      }
      return [MinX, MaxX, MinY, MaxY];
    },
    //改变二进制值
    changeTimeBinary() {
      let that = this;
      this.timeBinary.length = 0;
      $("#" + this.box_id + " table tbody")
        .find("td")
        .each(function(k) {
          let isSelected = $(this).hasClass("time-selected");
          if (isSelected) {
            that.timeBinary.push("1");
          } else {
            that.timeBinary.push("0");
          }
        });
      this.$emit("selectedBinaryTime", this.timeBinary.join(""));
    },

    //二进制数转换日期
    getBinaryConvertDate() {
      let binary = "";
      let timeOutHtml = [];
      let timeWeekSlot = []; //初始化周数数组
      let timeSpliceArr = [];
      let spliceStrHtml = [];
      binary = this.timeBinary.join("");
      _.times(7, y => {
        //初始化小时数组
        let timeHourSlot = [];
        let index;
        _.times(48, x => {
          //每个单元格
          //获取当前点击元素的位置
          index = y === 0 ? x : y * 48 + x;
          //获取td对应的二进制值
          let selectedStatus = binary.charAt(index);
          if (+selectedStatus === 1) {
            //组装保存进数组里
            if (
              +binary.charAt(index - 1) === 1 &&
              +binary.charAt(index - 2) === 1
            ) {
              //此位置（包含上一行）的前两个都为选中时
              if (x === 0 && +binary.charAt(index + 1) === 0) {
                //选中行里第一个，后一个表格没选中，加逗号
                timeHourSlot[timeHourSlot.length] = this.timeSlot[x] + ", ";
              } else if (x === 0 && +binary.charAt(index + 1) === 1) {
                //选中行里第一个，后一个表格已选中，不加逗号
                timeHourSlot[timeHourSlot.length] = this.timeSlot[x];
              } else if (x === 1 && +binary.charAt(index - 1) === 0) {
                //选中行里第二个，上一个表格没选中，加逗号
                timeHourSlot[timeHourSlot.length] = this.timeSlot[x] + ", ";
              } else if (x === 1 && +binary.charAt(index - 1) === 1) {
                //选中行里第二个，上一个表格已选中，前加-号，后加逗号
                timeHourSlot[timeHourSlot.length] =
                  "-" + this.timeSlot[x] + ", ";
              } else {
                //选中行里除第一、二的表格以外，前一个表格已经选中，此元素前加- 后加逗号
                timeHourSlot[timeHourSlot.length - 1] =
                  "-" + this.timeSlot[x] + ", ";
              }
            } else if (+binary.charAt(index - 1) === 1 && x > 0) {
              //选中的前一个已选中，且此次选中的不是行里第一个，此次选中的元素前加-后加逗号
              timeHourSlot[timeHourSlot.length] = "-" + this.timeSlot[x] + ", ";
            } else if (+binary.charAt(index + 1) !== 1 || x === 47) {
              //被选中的一个
              //选中的后一个没选中，或者此次选中的是行里最后一个，此次选中的元素加逗号
              timeHourSlot[timeHourSlot.length] = this.timeSlot[x] + ", ";
            } else {
              //选中的后一已选中，此次选中的元素不加逗号
              timeHourSlot[timeHourSlot.length] = this.timeSlot[x];
            }
          }
        });
        timeWeekSlot[y] = timeHourSlot;
      });
      this.displayHtml = "";
      //再次组装并输出数组
      _.times(7, y => {
        _.forEach(timeWeekSlot[y], (value, x) => {
          timeSpliceArr[y] = timeSpliceArr[y]
            ? timeSpliceArr[y] + timeWeekSlot[y][x]
            : timeWeekSlot[y][x];
        });
        if (timeSpliceArr[y]) {
          timeSpliceArr[y] = timeSpliceArr[y].substring(
            0,
            timeSpliceArr[y].length - 2
          );
          let temp = timeSpliceArr[y];
          let temp1 = temp.split(",");
          let transformTime = this.displayTimeSlot(temp1);
          timeOutHtml.push(transformTime);
          spliceStrHtml.push(
            `<div>星期${this.weekData[y]}(${transformTime})</div>`
          );
        }
      });
      this.displayHtml = spliceStrHtml.join("");
      this.$emit("selectedTimeStr", timeOutHtml.join(";"));
    },
    /**
     * 展示时间段
     * */
    displayTimeSlot(timeArray) {
      let temp = [];
      let afterHour = "";
      _.forEach(timeArray, (value, index) => {
        afterHour = _.trim(
          value.indexOf("-") !== -1 ? value.split("-")[1] : value
        );
        let halfHour = this.transFormHalfHour(value);
        let halfTotalMinutes = this.calculationMinutes(
          halfHour[0],
          halfHour[1]
        );
        let transFormHalf = this.transFormMinuteToHour(+halfTotalMinutes - 30);
        let allTemp = afterHour
          ? transFormHalf + "-" + afterHour
          : transFormHalf;
        temp.push(allTemp);
      });
      return temp.join(",");
    },
    //更新操作
    refreshTable() {
      //解绑鼠标移动监听事件
      $("#" + this.box_id + " table tbody tr td").unbind("mouseover");
      //初始化表格的在此次选中状态
      $("#" + this.box_id + " table tbody tr td").attr("tdState", "");
      //改变二进制值
      this.changeTimeBinary();
      //改变日期显示
      this.getBinaryConvertDate();
    },

    //二进制数赋值选中表格
    binarySelected() {
      if (this.defaultBinaryTime) {
        _.times(336, i => {
          let td_selected = this.defaultBinaryTime.charAt(i);
          if (+td_selected !== 0) {
            $("#" + this.box_id + " table tbody tr td")
              .eq(i)
              .addClass(this.selectedCls);
          }
        });
        this.$nextTick(function() {
          //更新操作，显示文字形日期
          this.refreshTable();
        });
      }
    },
    //点击选中或去掉选中整行、整列
    selectTdClick(startTdIndex, endTdIndex, Selected) {
      let MinX = null;
      let MaxX = null;
      let MinY = null;
      let MaxY = null;
      let selectedTrue = 0;
      let selectedFalse = 0;

      let coordinate = this.getCoordinate(startTdIndex, endTdIndex);
      MinX = coordinate[0];
      MaxX = coordinate[1];
      MinY = coordinate[2];
      MaxY = coordinate[3];
      MaxY = MaxY === 7 ? MaxY - 1 : MaxY;
      //列出此列当中的表格选中状态
      for (let i = MinY; i <= MaxY; i++) {
        for (let j = MinX; j <= MaxX; j++) {
          let selectedTR = $("#" + this.box_id + " table tbody tr ").eq(i);
          let tdClass = $("td", selectedTR)
            .eq(j)
            .hasClass("time-selected");
          selectedTrue = tdClass ? 1 : 0;
          selectedFalse = tdClass ? 0 : 1;
        }
      }

      //执行选中或去掉选中方法
      for (let i = MinY; i <= MaxY; i++) {
        for (let j = MinX; j <= MaxX; j++) {
          let selectTR = $("#" + this.box_id + " table tbody tr ").eq(i);
          let tdClass = $("td", selectTR)
            .eq(j)
            .attr("class");
          //一列当中存在已选中与未选中的表格处理:整列全部选中
          if (selectedTrue === 1 && selectedFalse === 1) {
            $("td", selectTR)
              .eq(j)
              .addClass(this.selectedCls);
          } else if (selectedFalse === 1) {
            //一列当中只存在未选中的表格处理:整列全部选中
            $("td", selectTR)
              .eq(j)
              .addClass(this.selectedCls);
          } else {
            //一列当中只存在已选中的表格处理:整列全部去掉选中
            $("td", selectTR)
              .eq(j)
              .removeClass(this.selectedCls);
          }
        }
      }
      this.changeTimeBinary();
      this.getBinaryConvertDate();
    },
    /**
     * 转换当前的Hour为Minutes
     * */
    transFormHalfHour(value) {
      let tempHalfHour = 0;
      if (value.indexOf("-") != -1) {
        let tempHalf = value.split("-");
        tempHalfHour = tempHalf[0].split(":");
      } else {
        tempHalfHour = value.split(":");
      }
      return tempHalfHour;
    },
    /**
     * 时间段转换分钟
     */
    calculationMinutes(hour, minutes) {
      return +hour * 60 + +minutes;
    },
    /**
     *分钟转换时间段
     **/
    transFormMinuteToHour(minutes) {
      let hour = parseInt(+minutes / 60);
      minutes = +minutes % 60;
      hour = hour.toString().padStart(2, "0");
      minutes = minutes.toString().padStart(2, "0");
      return hour + ":" + minutes;
    },
    /*二进制获取转换后的时间*/
    getBinaryToTime(binary) {
      return this.getBinaryConvertDate(binary);
    }
  }
};
</script>
<style lang="css" scoped>
.table-time-selected {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
  text-align: left;
  border: 0;
}
th,
td {
  margin: 0;
  padding: 0;
}
.plug-timer-grid {
  width: 100%;
  background: #f8f9fa;
}
.plug-timer-grid td,
.plug-timer-grid th {
  border: 1px solid #eee;
  text-align: center;
  font-size: 12px;
  color: #333;
}
.time-selected {
  background-color: #6a7398;
}
.plug-timer-grid {
  border-collapse: collapse;
  z-index: 4;
}

.plug-timer-grid thead tr {
  display: table-row;
  vertical-align: inherit;
  border-color: inherit;
  height: 35px;
}

table td {
  height: 30px;
  max-width: 5px;
  border: 1px solid #eee;
  font-size: 12px;
  text-align: center;
  vertical-align: middle;
  overflow: hidden;
  transition: background 0.5s;
  -webkit-transition: background 0.5s;
}

.plug-timer-grid tbody th {
  width: 4%;
  background: #f8f9fa;
}
.plug-timer-grid tbody tr {
  background: #fff;
}
.plug-timer-grid tbody tr td {
  width: 2%;
}
.pull-left-info {
  color: #333;
  font-size: 12px;
  cursor: pointer;
}
.duration-tipline {
  line-height: 35px;
  width: 100%;
  font-size: 12px;
}
.duration-tipline .color-box {
  display: inline-block;
  height: 14px;
  width: 14px;
  border: 1px solid rgba(57, 73, 103, 0.2);
  vertical-align: middle;
  margin-right: 5px;
}
.duration-tipline span {
  display: inline-block;
  vertical-align: middle;
}
.duration-tipline .color-box.color-blue {
  height: 14px;
  width: 14px;
  border-color: #6a7398;
  background: #6a7398;
}
.duration-tipline .color-box + span {
  margin-right: 15px;
}
.duration-tipline .weektip {
  color: #888;
  padding-left: 5px;
}
.duration-tipline .emptied {
  float: right;
  padding-right: 10px;
  color: #6a7398;
  cursor: pointer;
}
.tdmouse-hover {
  background-color: #eee;
}
.plug-timer-grid tbody tr td.table-footer {
  text-align: left;
  background: #f8f9fa;
}
.plug-timer-grid tbody tr td.table-footer .left {
  display: inline-block;
  text-align: center;
  margin-left: 1%;
}
</style>
